/*
	Kleines Demo-Programm fuer Szenenmanagement und Steuerung
*/

#include <irrlicht.h>
#include <Middleware.h>
#include <driverChoice.h>
#include <Misc.h>

#pragma comment(lib, "Irrlicht.lib")

using namespace irr;

int x_res = 640;
int y_res = 480;

int main(int argc, char *argv[]){

	// ask user for driver
	video::E_DRIVER_TYPE driverType=driverChoiceConsole();
	if (driverType==video::EDT_COUNT)
		return -1;

	//Device erstellen
	IrrlichtDevice *device = createDevice(driverType, 
		core::dimension2d<u32>(x_res, y_res), 16, false, false, false);

	if (device == 0)
		return -1; // could not create selected driver.

	//Fenstertitel setzen
	core::stringw tmp = L"Philipps Irrlicht Example";
	device->setWindowCaption(tmp.c_str());

	//Treiber und SceneManager laden
	video::IVideoDriver* driver = device->getVideoDriver();
	scene::ISceneManager* smgr = device->getSceneManager();

	/*--------------ab hier: Objekte erstellen--------------*/
	//den Mauszeiger loswerden
	device->getCursorControl()->setPosition(x_res / 2, y_res / 2);

	//einen Wuerfel, positioniert direkt ueber einem Feld des Bodens
	/*scene::ISceneNode * cube1 = smgr->addCubeSceneNode(2.5f);
	cube1->setMaterialTexture(0, driver->getTexture("media/wall.bmp"));
	//cube1->setPosition(core::vector3df(-6.25f, 1.8f, 1.25f)); //x=-1.25
	cube1->setMaterialFlag(video::EMF_LIGHTING, false);
	cube1->setID(IDFlag_IsPickable | IDFlag_IsHighlightable);
	cube1->setName("Cube1");*/

	scene::IMesh *cube1_mesh = smgr->getMesh("media/modelle/ecke4.3ds");
	scene::IMeshSceneNode *cube1 = smgr->addMeshSceneNode(cube1_mesh);
	cube1->setScale(core::vector3df(1.25f, 1.25f, 1.25f));
	cube1->setPosition(core::vector3df(-8.75f, 1.8f, 1.25f));
	cube1->setMaterialFlag(video::EMF_LIGHTING, false);
	cube1->setID(IDFlag_IsPickable | IDFlag_IsHighlightable);
	cube1->setName("Ecke");

	//einen Wuerfel mit Kantenlaenge 2.5
	scene::ISceneNode *cube2 = smgr->addCubeSceneNode(2.5f);
	cube2->setMaterialTexture(0, driver->getTexture("media/wall.bmp"));
	cube2->setPosition(core::vector3df(1.25f, 1.8f, 1.25f)); //1.25, y=1.8, 1.25
	cube2->setMaterialFlag(video::EMF_LIGHTING, false);
	cube2->setID(IDFlag_IsPickable | IDFlag_IsHighlightable);
	cube2->setName("Cube2");

	//noch zwei cubes fuer Kollisionstests
	scene::ISceneNode *cube3 = smgr->addCubeSceneNode(2.5f);
	cube3->setMaterialTexture(0, driver->getTexture("media/wall.bmp"));
	cube3->setPosition(core::vector3df(-3.75f, 1.8f, 3.75f));
	cube3->setMaterialFlag(video::EMF_LIGHTING, false);
	cube3->setID(IDFlag_IsPickable | IDFlag_IsHighlightable);
	cube3->setName("Cube3");

	scene::ISceneNode *cube4 = smgr->addCubeSceneNode(2.5f);
	//cube4->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
	cube4->setMaterialTexture(0, driver->getTexture("media/wall.bmp"));
	cube4->setPosition(core::vector3df(-3.75f, 1.8f, -1.25f));
	cube4->setMaterialFlag(video::EMF_LIGHTING, false);
	cube4->setID(IDFlag_IsPickable | IDFlag_IsHighlightable);
	cube4->setName("Cube4");

	//dann den Boden mit Schachbrettmuster, Breite pro Feld: 2.5
	scene::IAnimatedMesh * groundMesh= smgr->addHillPlaneMesh("Ground", core::dimension2d<f32>(20.0f, 20.0f), 
		core::dimension2d<u32>(2, 2),0,0.0f,core::dimension2df(0.0f, 0.0f),core::dimension2df(2.0f, 2.0f));
	scene::ISceneNode * ground = smgr->addMeshSceneNode(groundMesh);
	ground->setMaterialTexture(0, driver->getTexture("media/schach.jpg"));
	ground->setMaterialFlag(video::EMF_LIGHTING, false);
	ground->setName("Ground");
	ground->setID(ID_IsNotPickable);
	
	//und die Kamera
	scene::ICameraSceneNode * camera = smgr->addCameraSceneNode();
	camera->setPosition(core::vector3df(0, 0, -25));
	camera->setTarget(core::vector3df(0, 0, 0));
	core::vector3df v = camera->getPosition();
	v.rotateYZBy(45.0f);
	camera->setPosition(v);
	camera->setID(ID_IsNotPickable);

	/*--------------ab hier: CollisionDetection einrichten--------------*/
	//zuerst fuer jedes Objekt ein TriangleSelector
	scene::ITriangleSelector * cube1Selector = smgr->createTriangleSelector(cube1_mesh, cube1);
	cube1->setTriangleSelector(cube1Selector);

	/*scene::ITriangleSelector * cube1Selector = smgr->createTriangleSelectorFromBoundingBox(cube1);
	cube1->setTriangleSelector(cube1Selector);*/

	scene::ITriangleSelector * cube2Selector = smgr->createTriangleSelectorFromBoundingBox(cube2);
	cube2->setTriangleSelector(cube2Selector);

	scene::ITriangleSelector * cube3Selector = smgr->createTriangleSelectorFromBoundingBox(cube3);
	cube3->setTriangleSelector(cube3Selector);

	scene::ITriangleSelector * cube4Selector = smgr->createTriangleSelectorFromBoundingBox(cube4);
	cube4->setTriangleSelector(cube4Selector);

	scene::ITriangleSelector * groundSelector = smgr->createTriangleSelectorFromBoundingBox(ground);
	ground->setTriangleSelector(groundSelector);

	//dann alle Selectors fuer cube2 in einem MetaSelector zusammenfassen
	scene::IMetaTriangleSelector * metaSelector = smgr->createMetaTriangleSelector();
	metaSelector->addTriangleSelector(groundSelector);
	metaSelector->addTriangleSelector(cube1Selector);
	metaSelector->addTriangleSelector(cube3Selector);
	metaSelector->addTriangleSelector(cube4Selector);

	//und dann einen AnimatedSceneNodeCollisionResponse-dingens fuer jedes Objekt
	scene::ISceneNodeAnimator* cube2Anim = smgr->createCollisionResponseAnimator(metaSelector, cube2, 
		core::vector3df(1.24f, 1.24f, 1.24f), core::vector3df(0, -9.81f, 0));
	metaSelector->drop();
	cube2->addAnimator(cube2Anim);
	cube2Anim->drop();

	//metaSelector neu aufbauen fuer cube1 (muss leider sein)
	metaSelector = smgr->createMetaTriangleSelector();
	metaSelector->addTriangleSelector(cube2Selector);
	metaSelector->addTriangleSelector(cube3Selector);
	metaSelector->addTriangleSelector(cube4Selector);
	metaSelector->addTriangleSelector(groundSelector);
	scene::ISceneNodeAnimator* cube1Anim1 = smgr->createCollisionResponseAnimator(metaSelector, cube1, 
		core::vector3df(1.24f, 1.24f, 1.24f), core::vector3df(0, -9.81f, 0));
	scene::ISceneNodeAnimator* cube1Anim2 = smgr->createCollisionResponseAnimator(metaSelector, cube1, 
		core::vector3df(1.24f, 1.24f, 1.24f), core::vector3df(0, 0.0f, 0), core::vector3df(-2.5f, 0.0f, 0.0f));
	scene::ISceneNodeAnimator* cube1Anim3 = smgr->createCollisionResponseAnimator(metaSelector, cube1, 
		core::vector3df(1.24f, 1.24f, 1.24f), core::vector3df(0, 0.0f, 0), core::vector3df(0.0f, 0.0f, -2.5f));
	metaSelector->drop();
	cube1->addAnimator(cube1Anim1);
	cube1Anim1->drop();
	cube1->addAnimator(cube1Anim2);
	cube1Anim2->drop();
	cube1->addAnimator(cube1Anim3);
	cube1Anim3->drop();

	//metaSelector neu aufbauen fuer cube3 (muss leider sein)
	metaSelector = smgr->createMetaTriangleSelector();
	metaSelector->addTriangleSelector(cube2Selector);
	metaSelector->addTriangleSelector(cube1Selector);
	metaSelector->addTriangleSelector(cube4Selector);
	metaSelector->addTriangleSelector(groundSelector);
	scene::ISceneNodeAnimator* cube3Anim = smgr->createCollisionResponseAnimator(metaSelector, cube3, 
		core::vector3df(1.24f, 1.24f, 1.24f), core::vector3df(0, -9.81f, 0));
	metaSelector->drop();
	cube3->addAnimator(cube3Anim);
	cube3Anim->drop();

	//metaSelector neu aufbauen fuer cube4 (muss leider sein)
	metaSelector = smgr->createMetaTriangleSelector();
	metaSelector->addTriangleSelector(cube2Selector);
	metaSelector->addTriangleSelector(cube3Selector);
	metaSelector->addTriangleSelector(cube1Selector);
	metaSelector->addTriangleSelector(groundSelector);
	scene::ISceneNodeAnimator* cube4Anim = smgr->createCollisionResponseAnimator(metaSelector, cube4, 
		core::vector3df(1.24f, 1.24f, 1.24f), core::vector3df(0, -9.81f, 0));
	metaSelector->drop();
	cube4->addAnimator(cube4Anim);
	cube4Anim->drop();
	
	//Selectors weg
	cube1Selector->drop();
	cube2Selector->drop();
	cube3Selector->drop();
	cube4Selector->drop();
	groundSelector->drop();

	/*--------------ab hier: Szenenaufbau fertig, jetzt kommt die Action!--------------*/

	//die Steuerungsvariablen festlegen
	ControllerParams * params = (ControllerParams*)malloc(sizeof(ControllerParams));
	params->max_x = x_res;
	params->max_y = y_res;
	params->max_world_x = 17.5f;
	params->max_world_z = 17.5f;
	params->cursorStep = 3.0f; //0.1
	params->moveStep = 2.5f;
	params->camStep = 1.0f;
	params->rotateStep = 90.0f;
	params->cameraMax = 85.0f;
	params->cameraMin = 10.0f;
	params->device = device;
	params->driver = driver;
	params->smgr = smgr;
	params->cursor = device->getCursorControl();
	params->objects[0] = camera;
	params->objects[1] = cube1;
	params->objects[2] = cube2;
	params->objects[3] = cube3;
	params->objects[4] = cube4;
	params->objects[5] = ground;
	//params->objects[6] = cursor;

	//alle fuer die Steuerung relevanten Objekte an die Middleware uebergeben
	printf("starte MW...\n");
	int mw = initMiddleware(params);
	printf("fertig mit MW...\n");

	int lastFPS = -1;

	int counter = -1;

	//Hauptschleife
	while(device->run()){

		//counter++;

		device->yield();

		driver->beginScene(true, true, video::SColor(255,113,113,133));
		smgr->drawAll();
		driver->endScene();

		int fps = driver->getFPS();

		if (lastFPS != fps)
		{
			core::stringw str = L"Philipp's Irrlicht Example [";
			str += driver->getName();
			str += "] FPS:";
			str += fps;

			device->setWindowCaption(str.c_str());
			lastFPS = fps;
		}

		/*if(counter == 1){
			core::aabbox3df box = cube1->getTransformedBoundingBox();
			core::vector3df edges[8]; 
			box.getEdges(edges);
			core::vector3df box_center = box.getCenter();
			printf("box_center: (%.2f, %.2f, %.2f)\n", box_center.X, box_center.Y, box_center.Z);
			printf("box_edge: (%.2f, %.2f, %.2f)\n", edges[0].X, edges[0].Y, edges[0].Z);
			printf("box_edge: (%.2f, %.2f, %.2f)\n", edges[1].X, edges[1].Y, edges[1].Z);
			printf("box_edge: (%.2f, %.2f, %.2f)\n", edges[2].X, edges[2].Y, edges[2].Z);
			printf("box_edge: (%.2f, %.2f, %.2f)\n", edges[3].X, edges[3].Y, edges[3].Z);
			printf("box_edge: (%.2f, %.2f, %.2f)\n", edges[4].X, edges[4].Y, edges[4].Z);
			printf("box_edge: (%.2f, %.2f, %.2f)\n", edges[5].X, edges[5].Y, edges[5].Z);
			printf("box_edge: (%.2f, %.2f, %.2f)\n", edges[6].X, edges[6].Y, edges[6].Z);
			printf("box_edge: (%.2f, %.2f, %.2f)\n", edges[7].X, edges[7].Y, edges[7].Z);
		}*/
	}

	//Aufraeumen
	releaseMiddleware();
	device->drop();
	free(params);
	return 0;
}